from rest_framework.views import APIView
from .utils import OAuthQQ
from rest_framework.response import Response
from rest_framework import status
from .models import OAuthQQUser
from rest_framework_jwt.views import api_settings
from rest_framework.generics import GenericAPIView
from .serializers import QQAuthUserSerializer


class QQAuthURLView(APIView):
    """提供QQ扫码登陆界面的链接给用户"""

    def get(self, request):
        # 获取到next参数,实现将来从哪里进入的登录界面,QQ登录成功后就回到哪里
        next = request.query_params.get("next")

        # 创建QQ登录的工具对象(state只需要传递一次,后面一直带着)
        oauth = OAuthQQ(state=next)

        # 生成QQ扫码登录的链接(要体现面向对象的封装思想,视图中只写逻辑,不写过程)
        login_url = oauth.get_qq_login_url()

        return Response({"login_url": login_url})


class QQAuthUserView(GenericAPIView):
    """用户扫码登录的回调处理"""


    serializer_class = QQAuthUserSerializer

    def get(self, request):
        # 获取code
        code = request.query_params.get("code")
        print(code)
        if not code:
            return Response({"message": "缺少code"}, status=status.HTTP_400_BAD_REQUEST)

        # 创建QQ登录的工具类
        oauth = OAuthQQ()

        try:
            # 凭借code获取QQ服务器的access_token
            access_token = oauth.get_access_token(code)
            # 凭借access token获取QQ服务器中的openid
            openid = oauth.get_openid(access_token)
        except Exception as e:
            return Response({"message": "QQ服务器异常"}, status=status.HTTP_503_SERVICE_UNAVAILABLE)

        # 利用openid查询该QQ用户是否在美多商场中绑定过用户
        try:
            """
            get查询:一次只能查一条.
            查多了,报MultipleError的错;
            查少了,报DoesNotExist的错.
            """
            oauth_user = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 如果openid没绑定美多商城用户,创建用户并绑定到openid.
            # 需要发送openid给前端,在前端保存的一瞬间,让其知道是哪个QQ用户绑定的.
            access_token_openid = OAuthQQ.generate_save_user_token(openid)

            return Response({"access_token": access_token_openid})
        else:
            # 如果openid已绑定美多商城用户,直接生成JWT token,并返回
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            # 获取关联openid的user,oauth_user是一条查询记录,包含(openid和user)
            user = oauth_user.user

            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)

            # 向前段响应token,user_id,username
            return Response({
                "token": token,
                "user_id": user.id,
                "username": user.username
            })

    """
    Q:之前注册新用户,继承了CreateAPIView,指定了序列化器,所有的动作都交给序列化器完成.
      为什么现在也是注册新用户,却要重写post方法,自己开启校验?
    W:1.因为本次绑定用户中的模型类不止一个,有两个:
      当用户输入的手机号在美多商城中有记录, 用到美多商城的user,就不需要新建一个了;
      如果没有记录,就要创建新的user,使用的是OAuthQQUser模型类.
      2.因为CreateAPIView默认有个post方法,但是这个类中还有get请求.
    """

    def post(self, request):
        """给openid绑定用户数据"""

        """
        request.query_params:获取GET请求中的数据
        request.data:获取POST请求体中的数据
        """
        # 获取序列化器:注册的数据都在POST请求的请求体里面
        serializer = self.get_serializer(data=request.data)
        # 开启校验
        serializer.is_valid(raise_exception=True)
        # 保存校验的数据:save调create,create返回user,所以可以用user接收保存的数据
        user = serializer.save()

        # 生成JWT token响应
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 向前端响应token, user_id, username
        return Response({
            "token": token,
            "user_id": user.id,
            "username": user.username
        })
